home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / rw / readGIF.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  624 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1990, 1991, 1993 David Koblas.                          | */
  3. /* |   Permission to use, copy, modify, and distribute this software   | */
  4. /* |   and its documentation for any purpose and without fee is hereby | */
  5. /* |   granted, provided that the above copyright notice appear in all | */
  6. /* |   copies and that both that copyright notice and this permission  | */
  7. /* |   notice appear in supporting documentation.  This software is    | */
  8. /* |   provided "as is" without express or implied warranty.           | */
  9. /* +-------------------------------------------------------------------+ */
  10.  
  11.  
  12. #include <stdio.h>
  13. #include "image.h"
  14.  
  15. #define    MAXCOLORMAPSIZE        256
  16.  
  17. #define    TRUE    1
  18. #define    FALSE    0
  19.  
  20. #define CM_RED        0
  21. #define CM_GREEN    1
  22. #define CM_BLUE        2
  23.  
  24. #define    MAX_LWZ_BITS        12
  25.  
  26. #define INTERLACE        0x40
  27. #define LOCALCOLORMAP    0x80
  28. #define BitSet(byte, bit)    (((byte) & (bit)) == (bit))
  29.  
  30. #define    ReadOK(file,buffer,len)    (fread(buffer, len, 1, file) != 0)
  31.  
  32. #define LM_to_uint(a,b)            (((b)<<8)|(a))
  33.  
  34. struct {
  35.     unsigned int    Width;
  36.     unsigned int    Height;
  37.     unsigned char    ColorMap[3][MAXCOLORMAPSIZE];
  38.     unsigned int    BitPixel;
  39.     unsigned int    ColorResolution;
  40.     unsigned int    Background;
  41.     unsigned int    AspectRatio;
  42.     /*
  43.     **
  44.     */
  45.     int        GrayScale;
  46. } GifScreen;
  47.  
  48. static struct {
  49.     int    transparent;
  50.     int    delayTime;
  51.     int    inputFlag;
  52.     int    disposal;
  53. } Gif89 = { -1, -1, -1, 0 };
  54.  
  55. static int    verbose = FALSE;
  56. static int    showComment = FALSE;
  57.  
  58. static char    usage[] = "[-verbose] [-comments] [-image N] [GIFfile]";
  59.  
  60. static int ReadColorMap( FILE *fd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag );
  61. static int DoExtension( FILE *fd, int label);
  62. static int GetDataBlock( FILE *fd, unsigned char  *buf );
  63. static int GetCode( FILE *fd, int code_size, int flag );
  64. static int LWZReadByte( FILE *fd, int flag, int input_code_size );
  65. static Image *ReadImage( FILE *fd, int len, int height, int, unsigned char cmap[3][MAXCOLORMAPSIZE], int gray, int interlace, int ignore);
  66.  
  67. int    TestGIF(char *file)
  68. {
  69.     FILE    *fd = fopen(file, "r");
  70.     char    buf[10];
  71.     int    ret = 0;
  72.  
  73.     if (fd == NULL)
  74.         return 0;
  75.  
  76.     if (ReadOK(fd, buf, 6)) {
  77.         if ((strncmp(buf, "GIF", 3) == 0) && 
  78.              ((strcmp(buf + 3, "87a") != 0) || 
  79.               (strcmp(buf + 3, "89a") != 0)))
  80.             ret = 1;
  81.     }
  82.  
  83.     fclose(fd);
  84.  
  85.     return ret;
  86. }
  87.  
  88. Image *ReadGIF(char *file)
  89. {
  90.     unsigned char    buf[16];
  91.     unsigned char    c;
  92.     unsigned char    localColorMap[3][MAXCOLORMAPSIZE];
  93.     int        grayScale;
  94.     int        useGlobalColormap;
  95.     int        bitPixel;
  96.     int        imageCount = 0;
  97.     char        version[4];
  98.     int        imageNumber = 1;
  99.     FILE        *fd = fopen(file, "r");
  100.     Image        *image = NULL;
  101.  
  102.     if (fd == NULL)
  103.         return image;
  104.  
  105.     if (! ReadOK(fd,buf,6)) {
  106.         RWSetMsg("error reading magic number" );
  107.         fclose(fd);
  108.         return image;
  109.     }
  110.  
  111.     if (strncmp(buf,"GIF",3) != 0) {
  112.         RWSetMsg("not a GIF file" );
  113.         fclose(fd);
  114.         return image;
  115.     }
  116.  
  117.     strncpy(version, buf + 3, 3);
  118.     version[3] = '\0';
  119.  
  120.     if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
  121.         RWSetMsg("bad version number, not '87a' or '89a'" );
  122.         fclose(fd);
  123.         return image;
  124.     }
  125.  
  126.     if (! ReadOK(fd,buf,7)) {
  127.         RWSetMsg("failed to read screen descriptor" );
  128.         fclose(fd);
  129.         return image;
  130.     }
  131.  
  132.     GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
  133.     GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
  134.     GifScreen.BitPixel        = 2<<(buf[4]&0x07);
  135.     GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
  136.     GifScreen.Background      = buf[5];
  137.     GifScreen.AspectRatio     = buf[6];
  138.  
  139.     if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
  140.         if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap,
  141.                     &GifScreen.GrayScale)) {
  142.             RWSetMsg("error reading global colormap");
  143.             fclose(fd);
  144.             return image;
  145.         }
  146.     }
  147.  
  148.     if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
  149.         float    r;
  150.         r = ( (float) GifScreen.AspectRatio + 15.0 ) / 64.0;
  151.         /*
  152.         pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  153.             r < 1.0 ? 'x' : 'y',
  154.             r < 1.0 ? 1.0 / r : r );
  155.         */
  156.     }
  157.  
  158.     do {
  159.         if (! ReadOK(fd,&c,1)) {
  160.             RWSetMsg("EOF / read error on image data" );
  161.             fclose(fd);
  162.             return image;
  163.         }
  164.  
  165.         if (c == ';') {        /* GIF terminator */
  166.             if (imageCount < imageNumber) {
  167.                 RWSetMsg("only %d image%s found in file",
  168.                      imageCount, imageCount>1?"s":"" );
  169.                 fclose(fd);
  170.                 return image;
  171.             }
  172.         }
  173.  
  174.         if (c == '!') {     /* Extension */
  175.             if (! ReadOK(fd,&c,1)) {
  176.                 RWSetMsg("OF / read error on extention function code");
  177.                 return image;
  178.             }
  179.             DoExtension(fd, c);
  180.             continue;
  181.         }
  182.  
  183.         if (c != ',') {        /* Not a valid start character */
  184.             /*
  185.             pm_message("bogus character 0x%02x, ignoring", (int) c );
  186.             */
  187.             continue;
  188.         }
  189.  
  190.         ++imageCount;
  191.  
  192.         if (! ReadOK(fd,buf,9)) {
  193.             RWSetMsg("couldn't read left/top/width/height");
  194.             fclose(fd);
  195.             return image;
  196.         }
  197.  
  198.         useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
  199.  
  200.         bitPixel = 1<<((buf[8]&0x07)+1);
  201.  
  202.         if (! useGlobalColormap) {
  203.             if (ReadColorMap(fd, bitPixel, localColorMap, &grayScale)) {
  204.                 RWSetMsg("error reading local colormap" );
  205.                 return NULL;
  206.             }
  207.             image = ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  208.                   LM_to_uint(buf[6],buf[7]), 
  209.                   bitPixel, localColorMap, grayScale,
  210.                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  211.         } else {
  212.             image = ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  213.                   LM_to_uint(buf[6],buf[7]), 
  214.                   GifScreen.BitPixel, GifScreen.ColorMap, GifScreen.GrayScale,
  215.                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  216.         }
  217.     } while (image == NULL);
  218.  
  219.     return image;
  220. }
  221.  
  222. static int
  223. ReadColorMap(fd,number,buffer,gray)
  224. FILE        *fd;
  225. int        number;
  226. unsigned char    buffer[3][MAXCOLORMAPSIZE];
  227. int        *gray;
  228. {
  229.     int        i;
  230.     unsigned char    rgb[3];
  231.     int        flag;
  232.  
  233.     flag = TRUE;
  234.  
  235.     for (i = 0; i < number; ++i) {
  236.         if (! ReadOK(fd, rgb, sizeof(rgb))) {
  237.             RWSetMsg("bad colormap" );
  238.             return 1;
  239.         }
  240.  
  241.         buffer[CM_RED][i] = rgb[0] ;
  242.         buffer[CM_GREEN][i] = rgb[1] ;
  243.         buffer[CM_BLUE][i] = rgb[2] ;
  244.  
  245.         flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
  246.     }
  247.  
  248. #if 0
  249.     if (flag)
  250.         *gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
  251.     else
  252.         *gray = PPM_TYPE;
  253. #else    
  254.     *gray = 0;
  255. #endif
  256.  
  257.     return FALSE;
  258. }
  259.  
  260. static int
  261. DoExtension(fd, label)
  262. FILE    *fd;
  263. int    label;
  264. {
  265.     static char    buf[256];
  266.     char        *str;
  267.  
  268.     switch (label) {
  269.     case 0x01:        /* Plain Text Extension */
  270.         str = "Plain Text Extension";
  271. #ifdef notdef
  272.         if (GetDataBlock(fd, (unsigned char*) buf) == 0)
  273.             ;
  274.  
  275.         lpos   = LM_to_uint(buf[0], buf[1]);
  276.         tpos   = LM_to_uint(buf[2], buf[3]);
  277.         width  = LM_to_uint(buf[4], buf[5]);
  278.         height = LM_to_uint(buf[6], buf[7]);
  279.         cellw  = buf[8];
  280.         cellh  = buf[9];
  281.         foreground = buf[10];
  282.         background = buf[11];
  283.  
  284.         while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  285.             PPM_ASSIGN(image[ypos][xpos],
  286.                     cmap[CM_RED][v],
  287.                     cmap[CM_GREEN][v],
  288.                     cmap[CM_BLUE][v]);
  289.             ++index;
  290.         }
  291.  
  292.         return FALSE;
  293. #else
  294.         break;
  295. #endif
  296.     case 0xff:        /* Application Extension */
  297.         str = "Application Extension";
  298.         break;
  299.     case 0xfe:        /* Comment Extension */
  300.         str = "Comment Extension";
  301.         while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  302.             /*
  303.             if (showComment)
  304.                 pm_message("gif comment: %s", buf );
  305.             */
  306.         }
  307.         return FALSE;
  308.     case 0xf9:        /* Graphic Control Extension */
  309.         str = "Graphic Control Extension";
  310.         (void) GetDataBlock(fd, (unsigned char*) buf);
  311.         Gif89.disposal    = (buf[0] >> 2) & 0x7;
  312.         Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
  313.         Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
  314.         if ((buf[0] & 0x1) != 0)
  315.             Gif89.transparent = buf[3];
  316.  
  317.         while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  318.             ;
  319.         return FALSE;
  320.     default:
  321.         str = buf;
  322.         sprintf(buf, "UNKNOWN (0x%02x)", label);
  323.         break;
  324.     }
  325.  
  326.     /* pm_message("got a '%s' extension", str ); */
  327.  
  328.     while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  329.         ;
  330.  
  331.     return FALSE;
  332. }
  333.  
  334. static int    ZeroDataBlock = FALSE;
  335.  
  336. static int
  337. GetDataBlock(fd, buf)
  338. FILE        *fd;
  339. unsigned char     *buf;
  340. {
  341.     unsigned char    count;
  342.  
  343.     if (! ReadOK(fd,&count,1)) {
  344.         /* pm_message("error in getting DataBlock size" ); */
  345.         return -1;
  346.     }
  347.  
  348.     ZeroDataBlock = count == 0;
  349.  
  350.     if ((count != 0) && (! ReadOK(fd, buf, count))) {
  351.         /* pm_message("error in reading DataBlock" ); */
  352.         return -1;
  353.     }
  354.  
  355.     return count;
  356. }
  357.  
  358. static int
  359. GetCode(fd, code_size, flag)
  360. FILE    *fd;
  361. int    code_size;
  362. int    flag;
  363. {
  364.     static unsigned char    buf[280];
  365.     static int        curbit, lastbit, done, last_byte;
  366.     int            i, j, ret;
  367.     unsigned char        count;
  368.  
  369.     if (flag) {
  370.         curbit = 0;
  371.         lastbit = 0;
  372.         done = FALSE;
  373.         return 0;
  374.     }
  375.  
  376.     if ( (curbit+code_size) >= lastbit) {
  377.         if (done) {
  378.             if (curbit >= lastbit)
  379.                 RWSetMsg("ran off the end of my bits" );
  380.             return -1;
  381.         }
  382.         buf[0] = buf[last_byte-2];
  383.         buf[1] = buf[last_byte-1];
  384.  
  385.         if ((count = GetDataBlock(fd, &buf[2])) == 0)
  386.             done = TRUE;
  387.  
  388.         last_byte = 2 + count;
  389.         curbit = (curbit - lastbit) + 16;
  390.         lastbit = (2+count)*8 ;
  391.     }
  392.  
  393.     ret = 0;
  394.     for (i = curbit, j = 0; j < code_size; ++i, ++j)
  395.         ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  396.  
  397.     curbit += code_size;
  398.  
  399.     return ret;
  400. }
  401.  
  402. static int
  403. LWZReadByte(fd, flag, input_code_size)
  404. FILE    *fd;
  405. int    flag;
  406. int    input_code_size;
  407. {
  408.     static int    fresh = FALSE;
  409.     int        code, incode;
  410.     static int    code_size, set_code_size;
  411.     static int    max_code, max_code_size;
  412.     static int    firstcode, oldcode;
  413.     static int    clear_code, end_code;
  414.     static int    table[2][(1<< MAX_LWZ_BITS)];
  415.     static int    stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  416.     register int    i;
  417.  
  418.     if (flag) {
  419.         set_code_size = input_code_size;
  420.         code_size = set_code_size+1;
  421.         clear_code = 1 << set_code_size ;
  422.         end_code = clear_code + 1;
  423.         max_code_size = 2*clear_code;
  424.         max_code = clear_code+2;
  425.  
  426.         GetCode(fd, 0, TRUE);
  427.         
  428.         fresh = TRUE;
  429.  
  430.         for (i = 0; i < clear_code; ++i) {
  431.             table[0][i] = 0;
  432.             table[1][i] = i;
  433.         }
  434.         for (; i < (1<<MAX_LWZ_BITS); ++i)
  435.             table[0][i] = table[1][0] = 0;
  436.  
  437.         sp = stack;
  438.  
  439.         return 0;
  440.     } else if (fresh) {
  441.         fresh = FALSE;
  442.         do {
  443.             firstcode = oldcode =
  444.                 GetCode(fd, code_size, FALSE);
  445.         } while (firstcode == clear_code);
  446.         return firstcode;
  447.     }
  448.  
  449.     if (sp > stack)
  450.         return *--sp;
  451.  
  452.     while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
  453.         if (code == clear_code) {
  454.             for (i = 0; i < clear_code; ++i) {
  455.                 table[0][i] = 0;
  456.                 table[1][i] = i;
  457.             }
  458.             for (; i < (1<<MAX_LWZ_BITS); ++i)
  459.                 table[0][i] = table[1][i] = 0;
  460.             code_size = set_code_size+1;
  461.             max_code_size = 2*clear_code;
  462.             max_code = clear_code+2;
  463.             sp = stack;
  464.             firstcode = oldcode =
  465.                     GetCode(fd, code_size, FALSE);
  466.             return firstcode;
  467.         } else if (code == end_code) {
  468.             int        count;
  469.             unsigned char    buf[260];
  470.  
  471.             if (ZeroDataBlock)
  472.                 return -2;
  473.  
  474.             while ((count = GetDataBlock(fd, buf)) > 0)
  475.                 ;
  476.  
  477.             if (count != 0) {
  478.                 /*
  479.                 pm_message("missing EOD in data stream (common occurence)");
  480.                 */
  481.             }
  482.             return -2;
  483.         }
  484.  
  485.         incode = code;
  486.  
  487.         if (code >= max_code) {
  488.             *sp++ = firstcode;
  489.             code = oldcode;
  490.         }
  491.  
  492.         while (code >= clear_code) {
  493.             *sp++ = table[1][code];
  494.             if (code == table[0][code]) {
  495.                 RWSetMsg("circular table entry BIG ERROR");
  496.             }
  497.             code = table[0][code];
  498.         }
  499.  
  500.         *sp++ = firstcode = table[1][code];
  501.  
  502.         if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  503.             table[0][code] = oldcode;
  504.             table[1][code] = firstcode;
  505.             ++max_code;
  506.             if ((max_code >= max_code_size) &&
  507.                 (max_code_size < (1<<MAX_LWZ_BITS))) {
  508.                 max_code_size *= 2;
  509.                 ++code_size;
  510.             }
  511.         }
  512.  
  513.         oldcode = incode;
  514.  
  515.         if (sp > stack)
  516.             return *--sp;
  517.     }
  518.     return code;
  519. }
  520.  
  521. static Image *ReadImage(FILE *fd, int len, int height, int cmapSize,
  522.         unsigned char cmap[3][MAXCOLORMAPSIZE], 
  523.         int gray, int interlace, int ignore)
  524. {
  525.     Image        *image;
  526.     unsigned char    c;    
  527.     int        i, v;
  528.     int        xpos = 0, ypos = 0, pass = 0;
  529.  
  530.     /*
  531.     **  Initialize the Compression routines
  532.     */
  533.     if (! ReadOK(fd,&c,1)) {
  534.         RWSetMsg("EOF / read error on image data" );
  535.         return NULL;
  536.     }
  537.  
  538.     if (LWZReadByte(fd, TRUE, c) < 0) {
  539.         RWSetMsg("error reading image" );
  540.         return NULL;
  541.     }
  542.  
  543.     /*
  544.     **  If this is an "uninteresting picture" ignore it.
  545.     */
  546.     if (ignore) {
  547.         /*
  548.         if (verbose)
  549.             pm_message("skipping image..." );
  550.         */
  551.  
  552.         while (LWZReadByte(fd, FALSE, c) >= 0)
  553.             ;
  554.         return NULL;
  555.     }
  556.  
  557.     image = ImageNewCmap(len, height, cmapSize);
  558.  
  559.     for (i = 0; i < cmapSize; i++)
  560.         ImageSetCmap(image, i, cmap[CM_RED][i], 
  561.                 cmap[CM_GREEN][i], cmap[CM_BLUE][i]);
  562.  
  563.     /*
  564.     if (verbose)
  565.         pm_message("reading %d by %d%s GIF image",
  566.             len, height, interlace ? " interlaced" : "" );
  567.     */
  568.  
  569.     while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
  570.         image->data[xpos + ypos * len] = v;
  571.  
  572.         ++xpos;
  573.         if (xpos == len) {
  574.             xpos = 0;
  575.             if (interlace) {
  576.                 switch (pass) {
  577.                 case 0:
  578.                 case 1:
  579.                     ypos += 8; break;
  580.                 case 2:
  581.                     ypos += 4; break;
  582.                 case 3:
  583.                     ypos += 2; break;
  584.                 }
  585.  
  586.                 if (ypos >= height) {
  587.                     ++pass;
  588.                     switch (pass) {
  589.                     case 1:
  590.                         ypos = 4; break;
  591.                     case 2:
  592.                         ypos = 2; break;
  593.                     case 3:
  594.                         ypos = 1; break;
  595.                     default:
  596.                         goto fini;
  597.                     }
  598.                 }
  599.             } else {
  600.                 ++ypos;
  601.             }
  602.         }
  603.         if (ypos >= height)
  604.             break;
  605.     }
  606.  
  607. fini:
  608. #if 0
  609.     if (LWZReadByte(fd,FALSE,c)>=0)
  610.         pm_message("too much input data, ignoring extra...");
  611.  
  612.     if (verbose)
  613.         pm_message("writing a %s file",
  614.                 gray == PBM_TYPE ? "PBM" :
  615.                 gray == PGM_TYPE ? "PGM" :
  616.                 gray == PPM_TYPE ? "PPM" :
  617.                 "UNKNOWN!");
  618.  
  619.     pnm_writepnm(stdout, image, len, height, (pixval) 255, gray, 0 );
  620. #endif
  621.  
  622.     return image;
  623. }
  624.